package dev.langchain4j.model.chat.response;

import static dev.langchain4j.internal.Utils.quoted;
import static dev.langchain4j.internal.ValidationUtils.ensureNotBlank;
import static dev.langchain4j.internal.ValidationUtils.ensureNotEmpty;
import static dev.langchain4j.internal.ValidationUtils.ensureNotNegative;

import dev.langchain4j.Experimental;
import java.util.Objects;

/**
 * Represents a partial tool call.
 * Includes the index, ID, name, and a portion of the arguments.
 *
 * @see CompleteToolCall
 * @since 1.2.0
 */
@Experimental
public class PartialToolCall {

    private final int index;
    private final String id;
    private final String name;
    private final String partialArguments;

    public PartialToolCall(Builder builder) {
        this.index = ensureNotNegative(builder.index, "index");
        this.id = builder.id;
        this.name = ensureNotBlank(builder.name, "name");
        this.partialArguments = ensureNotEmpty(builder.partialArguments, "partialArguments");
    }

    /**
     * The index of the tool call, starting from 0 and increasing by 1.
     * When the LLM initiates multiple tool calls, this index helps correlate
     * the different {@link PartialToolCall}s with each other and with the final {@link CompleteToolCall}.
     */
    public int index() {
        return index;
    }

    /**
     * The unique identifier for the tool call, generated by the LLM provider.
     * Please note that some LLM providers (e.g., Google, Ollama) may omit this ID.
     */
    public String id() {
        return id;
    }

    /**
     * The name of the tool being invoked.
     */
    public String name() {
        return name;
    }

    /**
     * A portion of the arguments for the tool.
     * When combined, the arguments from all {@link PartialToolCall}s should form a complete and valid JSON string.
     */
    public String partialArguments() {
        return partialArguments;
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) return true;
        if (object == null || getClass() != object.getClass()) return false;
        PartialToolCall that = (PartialToolCall) object;
        return index == that.index
                && Objects.equals(id, that.id)
                && Objects.equals(name, that.name)
                && Objects.equals(partialArguments, that.partialArguments);
    }

    @Override
    public int hashCode() {
        return Objects.hash(index, id, name, partialArguments);
    }

    @Override
    public String toString() {
        return "PartialToolCall{" + "index="
                + index + ", id="
                + quoted(id) + ", name="
                + quoted(name) + ", partialArguments="
                + quoted(partialArguments) + '}';
    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {

        private int index;
        private String id;
        private String name;
        private String partialArguments;

        public Builder index(int index) {
            this.index = index;
            return this;
        }

        public Builder id(String id) {
            this.id = id;
            return this;
        }

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Builder partialArguments(String partialArguments) {
            this.partialArguments = partialArguments;
            return this;
        }

        public PartialToolCall build() {
            return new PartialToolCall(this);
        }
    }
}
